import { LinearAlgebraObject  } from "./common";


/**
 * 向量
 */
export interface Vec extends Float32Array {
  [index: number]: number;
}

export type VectorType = Vec | Vector

/**
 * 判断是否为vec类型
 * @param obj 
 * @returns 
 */
export function isVec(obj: any): obj is Vec {
  return obj instanceof Float32Array;
}

/**
 * 向量类型转换
 * @param vec 
 * @returns 
 */
export function Vec2Vector(vec: VectorType): Vector {
  if(isVec(vec)) {
    return new Vector(vec);
  }
  return vec
}

/**
 * Vector 类表示一个数学向量，继承自 LinearAlgebraObject。
 * 它提供操作和访问向量元素的方法。
 */
export class Vector extends LinearAlgebraObject {

  private _Vector: Float32Array;

  /**
   * 使用给定的数据构造一个向量。
   * @param {Float32Array | Array<number>} data - 初始化向量的数据。
   */
  constructor(data: Float32Array | Array<number>) {
    super(data.length, 1);
    this._Vector = new Float32Array(data);
  }

  /**
   * 获取向量的数据。
   * @return {Float32Array} 向量的数据。
   */
  get data(): Float32Array {
    return this._Vector;
  }

  /**
   * 获取向量的长度。
   * @return {number} 向量的长度。
   */
  get length(): number {
    return this._Vector.length;
  }

  /**
   * 获取指定索引处的值。
   * @param {number} index - 要获取的元素的索引。
   * @return {number} 指定索引处的值。
   * @throws {Error} 如果索引超出范围。
   */
  get(index: number): number {
    if(index < 0 || index >= this.length) {
      throw new Error("索引超出范围");
    }
    return this._Vector[index];
  }

  /**
   * 设置指定索引处的值。
   * @param {number} index - 要设置的元素的索引。
   * @param {number} value - 要设置的值。
   * @throws {Error} 如果索引超出范围。
   */
  set(index: number, value: number) {
    if(index < 0 || index >= this.length) {
      throw new Error("索引超出范围");
    }
    this._Vector[index] = value;
  }

  /**
   * 返回向量的字符串表示形式。
   * @return {String} 向量的字符串表示形式。
   */
  toString(): String {
    return `[${this._Vector.toString()}]`;
  }

  /**
   * 返回向量的迭代器，使其可以在 for...of 循环中使用。
   * @return {Iterator<number>} 向量的迭代器。
   */
  [Symbol.iterator](): Iterator<number> {
    let index = 0;
    let data = this._Vector;
    return {
      next(): IteratorResult<number> {
        if (index < data.length) {
          return { value: data[index++], done: false };
        } else {
          return { done: true } as IteratorResult<number>;
        }
      }
    };
  }

}


/**
 * 定义二维向量
 * @param x 定义二维向量的第一个分量
 * @param y 定义二维向量的第二个分量
 * @returns 一个包含两个分量的二维向量
 */
export function vec2(x: number, y: number): Vec {
  const out = new Float32Array(2) as Vec;
  out[0] = x;
  out[1] = y;

  return out;
}

/**
 * 定义三维向量
 * @param x 
 * @param y 
 * @param z 
 * @returns 
 */
export function vec3(x: number, y: number, z: number) {
  const out = new Float32Array(3) as Vec;
  out[0] = x;
  out[1] = y;
  out[2] = z;

  return out;
}

/**
 * 定义四维向量
 * @param x 
 * @param y 
 * @param z 
 * @param w 
 * @returns 
 */
export function vec4(x: number, y: number, z: number, w: number) {
  const out = new Float32Array(4) as Vec;
  out[0] = x;
  out[1] = y;
  out[2] = z;
  out[3] = w;

  return out;
}

/**
 * 定义零向量
 * @param length 
 * @returns 
 */
export function zeroVector(length: number): Vec {
  const out = new Float32Array(length) as Vec;
  out.fill(0);
  return out;
}

/**
 * 定义单位向量
 * @param length 
 * @returns 
 */
export function unitVector(length: number, index: number = 0): Vec {
  const out = new Float32Array(length) as Vec;
  if(index < 0 || index >= length) {
    throw new Error("索引超出范围");
  }
  out[index] = 1
  return out;
}


/**
 * 向量点乘
 * @param a 
 * @param b 
 * @returns 
 */
export function dot(a: VectorType, b: VectorType) {
  
  let v1: Vector = Vec2Vector(a);
  let v2: Vector = Vec2Vector(b);


  if(v1.length !== v2.length) {
    throw new Error("向量长度不一致");
  }

  let value: number = 0;
  for(let i = 0; i < v1.length; i++) {
    value += v1.get(i)* v2.get(i);
  }
  
  return value
}


/**
 * 向量加法
 * @param a 
 * @param b 
 * @returns 
 */
export function add(a: VectorType, b: VectorType) {

  let v1: Vector = Vec2Vector(a);
  let v2: Vector = Vec2Vector(b);

  if(v1.length !== v2.length) {
    throw new Error("向量长度不一致");
  }
  
  const v3 = new Vector(zeroVector(v1.length));

  for(let i = 0; i < v1.length; i++) {
    v3.set(i, v1.get(i) + v2.get(i));
  }
  
  return v3.data;
}


/**
 * 向量减法 - 左边减去右边
 * @param a 
 * @param b 
 * @returns 
 */
export function subtract(a: VectorType, b: VectorType) {
  
  let v1: Vector = Vec2Vector(a);
  let v2: Vector = Vec2Vector(b);

  if(v1.length !== v2.length) {
    throw new Error("向量长度不一致");
  }
  
  const v3 = new Vector(zeroVector(v1.length));

  for(let i = 0; i < v1.length; i++) {
    v3.set(i, v1.get(i) - v2.get(i));
  }
  
  return v3.data;
}


/**
 * 向量乘法 - 每个元素对应相乘
 * @param a 
 * @param b 
 * @returns 
 */
export function multiply(a: VectorType, b: VectorType) {
  let v1: Vector = Vec2Vector(a);
  let v2: Vector = Vec2Vector(b);
  
  if(v1.length !== v2.length) {
    throw new Error("向量长度不一致");
  }
  
  const v3 = new Vector(zeroVector(v1.length));
  
  for(let i = 0; i < v1.length; i++) {
    v3.set(i, v1.get(i) * v2.get(i));
  }
  
  return v3.data;
}


/**
 * 求向量的模长
 * @param a 
 * @returns 
 */
export function magnitude(a: VectorType) {
  let v1: Vector = Vec2Vector(a);
  let value: number = 0;
  for(let i = 0; i < v1.length; i++) {
    value += v1.get(i) * v1.get(i);
  }
  return Math.sqrt(value);
}

/**
 * 
 * @param a 
 * @param b 
 */
export function crossMultiple(a: VectorType, b: VectorType) {
  let v1: Vector = Vec2Vector(a);
  let v2: Vector = Vec2Vector(b);
  
  if(v1.length !== v2.length) {
    throw new Error("向量长度不一致");
  }
  const v3 = new Vector(zeroVector(v1.length));
  
  
}